package com.smartalarmclock.Model;

import java.util.HashSet;
import java.util.Set;

import com.smartalarmclock.Model.Exceptions.DataEntityDoesNotExistException;
import com.smartalarmclock.Model.Exceptions.PhoneContactDoesNotExistException;

import android.content.Context;

public final class ContactFactory implements IReferencingDataEntityFactory {

	// Contacts
	
	/**
	 * @return all contacts in the database
	 */
	public Set<IContact> GetAllContacts(Context context) {
		return Contact.GetAllContacts(context);
	}
	
	/**
	 * Queries a contact (single contact or group) by id
	 * @param context the context of the request
	 * @param id the id of the contact
	 * @return the contact with the given id.
	 */
	public IContact TryGetContactById(Context context, int id) {
		IContact contact = TryGetSingleContactById(context, id);
		if (contact != null) {
			return contact;
		}
		
		return TryGetGroupById(context, id);
	}
	
	// Single Contacts
	
	/**
	 * Creates a new single contact
	 * @param phoneContactId the phone contact id of the single contact
	 * @return the new single contact
	 */
	public ISingleContact CreateSingleContact(String phoneContactId) {
		return new SingleContact(phoneContactId);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param id the id of the SingleContact
	 * @return the SingleContact instance from the DB with the corresponding id
	 * @throws DataEntityDoesNotExistException if the SingleContact was not found
	 */
	public ISingleContact GetSingleContactById(Context context, int id) throws DataEntityDoesNotExistException {
		return SingleContact.GetSingleContactById(context, id);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param id the id of the SingleContact
	 * @return the SingleContact instance from the DB with the corresponding id, null if doesn't exist
	 */
	public ISingleContact TryGetSingleContactById(Context context, int id) {
		return SingleContact.TryGetSingleContactById(context, id);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param phoneContactId the id of the contact as it is saved in the phone's contact list
	 * @return the SingleContact instance from the DB with the corresponding phone contact id
	 * @throws DataEntityDoesNotExistException if the SingleContact was not found
	 */
	public ISingleContact GetSingleContactByPhoneContactId(Context context, String phoneContactId) throws DataEntityDoesNotExistException {
		return SingleContact.GetSingleContactByPhoneContactId(context, phoneContactId);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param phoneContactId the id of the contact as it is saved in the phone's contact list
	 * @return the SingleContact instance from the DB with the corresponding phone contact id, null if doesn't exist
	 */
	public ISingleContact TryGetSingleContactByPhoneContactId(Context context, String phoneContactId) {
		return SingleContact.TryGetSingleContactByPhoneContactId(context, phoneContactId);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param phoneNumber phone number of the contact
	 * @return the SingleContact instance from the DB with the corresponding phone number
	 * @throws PhoneContactDoesNotExistException if a contact with the given phone number does not exist in the phone's contacts database.
	 * @throws DataEntityDoesNotExistException if the SingleContact was not found.
	 */
	public ISingleContact GetSingleContactByPhoneNumber(Context context, String phoneNumber) throws PhoneContactDoesNotExistException, DataEntityDoesNotExistException {
		return SingleContact.GetSingleContactByPhoneNumber(context, phoneNumber);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param phoneNumber phone number of the contact
	 * @return the SingleContact instance from the DB with the corresponding phone number, null if doesn't exist
	 */
	public ISingleContact TryGetSingleContactByPhoneNumber(Context context, String phoneNumber) {
		return SingleContact.TryGetSingleContactByPhoneNumber(context, phoneNumber);
	}
	
	/**
	 * Queries the DB for all single contacts
	 * @param context the context of the request (the originating Activity)
	 * @return all SingleContacts in the DB
	 */
	public Set<ISingleContact> GetAllSingleContacts(Context context) {
		return SingleContact.GetAllSingleContacts(context);
	}
	
	// Groups
	
	/**
	 * Creates a new group instance
	 * @param name the name of the group
	 */
	public IGroup CreateGroup(String name) {
		return new Group(name);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param id the id of the group
	 * @return the Group instance from the DB with the corresponding id
	 * @throws DataEntityDoesNotExistException if the group was not found
	 */
	public IGroup GetGroupById(Context context, int id) throws DataEntityDoesNotExistException {
		return Group.GetGroupById(context, id);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param id the id of the group
	 * @return the Group instance from the DB with the corresponding id, null if doesn't exist
	 */
	public IGroup TryGetGroupById(Context context, int id) {
		return Group.TryGetGroupById(context, id);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param name the name of the group
	 * @return the Group instance from the DB with the corresponding name
	 * @throws DataEntityDoesNotExistException if the group was not found
	 */
	public IGroup GetGroupByName(Context context, String name) throws DataEntityDoesNotExistException {
		return Group.GetGroupByName(context, name);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @param name the name of the group
	 * @return the Group instance from the DB with the corresponding name, null if doesn't exist
	 */
	public IGroup TryGetGroupByName(Context context, String name) {
		return Group.TryGetGroupByName(context, name);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @return all the contact groups
	 */
	public Set<IGroup> GetAllGroups(Context context) {
		return Group.GetAllGroups(context);
	}
	
	/**
	 * @param context the context of the request (the originating Activity)
	 * @return all groups containing the given contact.
	 */
	public Set<IGroup> GetGroupsByContact(Context context, IContact contact) {
		return Group.GetGroupsByContact(context, contact);
	}

	/**
	 * @param context the context of the request
	 * @param referencedDataEntity the referencing entity
	 * @return a set of referencing entities for the given referenced entity
	 * @throws DataEntityDoesNotExistException if the referencing entities do not exist. If this is thrown
	 * something went wrong with the handling of the references.
	 */
	@Override
	public Set<IReferencingDataEntity> GetReferencingEntities(Context context, IReferencedDataEntity referencedDataEntity) throws DataEntityDoesNotExistException {
		HashSet<IReferencingDataEntity> groups = new HashSet<IReferencingDataEntity>();
		for (IGroup group : GetGroupsByContact(context, (IContact)referencedDataEntity)) {
			groups.add(group);
		}
		return groups;
	}
}
